﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataRepositoryLayer.Interfaces;
using ModelLayer;
using ModelLayer.DTO;
using System.Diagnostics;

namespace DataRepositoryLayer.Classes
{
    public class BatteryReservationRepository : GenericDataRepository<BatteryReservation>, IBatteryReservationRepository
    {
        public BatteryReservationRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
        {

        }

        public IList<BatteryToReserveDTO> GetReservationsOnRoute(IList<PointReservationDTO> desiredReservations, IList<Battery> possibleBatteriesToReserve,
            BatteryType desiredType)
        {
            IList<BatteryToReserveDTO> finalBatteries = new List<BatteryToReserveDTO>();
            int typeId = desiredType.id;


            IDictionary<int, PointReservationDTO> idsToDTOs = new Dictionary<int, PointReservationDTO>();
            int length = desiredReservations.Count;
            int[] battery_ids = possibleBatteriesToReserve.Select(b => b.id).ToArray();
            foreach(int id in battery_ids)
            {
                Debug.WriteLine("Battery id => " + id);
            }

            for (int i = 0; i < length; i++)
            {
                idsToDTOs.Add(desiredReservations[i].StationId, desiredReservations[i]);
            }

            IList<BatteryReservation> currentReservations = GetList(r => battery_ids.Contains(r.battery_id));
            Debug.WriteLine("current reservations count => " + currentReservations.Count);
            Debug.WriteLine("Charge time => " + desiredType.average_charging_time);
            foreach (Battery battery in possibleBatteriesToReserve)
            {
                //Debug.WriteLine("Loop start");
                int stationId = battery.station_id;
                if (idsToDTOs.ContainsKey(stationId))
                {
                    //Debug.WriteLine("Key found");
                    DateTime desiredReservationTime = idsToDTOs[stationId].ReservationTime;
                    if (!currentReservations.Any(r =>
                        Math.Abs(r.time_of_reservation.Ticks - desiredReservationTime.Ticks) < (long)desiredType.average_charging_time * 10000 * 1000 * 60 &&
                        r.battery_id == battery.id))
                    {
                        Debug.WriteLine("No evil doers found");
                        finalBatteries.Add(new BatteryToReserveDTO
                        {
                            BatteryToReserve = battery,
                            Distance = idsToDTOs[stationId].Distance,
                            ReservationTime = desiredReservationTime
                        });
                        idsToDTOs.Remove(stationId);
                    }
                    else
                    {
                        Debug.WriteLine("Unbookable");
                    }
                }
            }
            if (finalBatteries.Count != desiredReservations.Count)
            {
                return null;
            }
            return finalBatteries;
        }


        public bool TryToReserveSingle(Battery battery, BatteryType type)
        {
            DateTime now = DateTime.Now;
            if(GetList(br => br.battery_id == battery.id && 
                Math.Abs(br.time_of_reservation.Ticks - now.Ticks) < type.average_charging_time * 10000 * 1000 * 60).Count == 0)
            {
                BatteryReservation reservation = new BatteryReservation() { time_of_reservation = now, battery_id = battery.id, completed = true };
                Add(reservation);
                return true;
            }
            return false;
        }


        public IList<BatteryReservation> GetCurrentReservations()
        {
            return GetList(r => !r.completed);
        }


        public IList<BatteryReservation> GetCurrentReservations(Station station)
        {
            return GetList(r => !r.completed && station.Batteries.Select(b => b.id).Contains(r.battery_id));
        }
    }
}
